/******************************************************************************
	This file is a part of the Snapshot Bioinformatics Project

	Copyright (C) 2012-2013 Jarom Schow

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/

#include "DbXrefInsertBuilder.h"

#include <QtCore/QVariant>
#include <QtCore/QFile>

#include "SqlServer.h"

using namespace Bio;

const QString	c_dbXRefSql = "INSERT INTO dbxref(dbxref_id, dbname, accession, version) VALUES ";
const QString	c_bioentrySql = "INSERT INTO bioentry_dbxref(bioentry_id, dbxref_id, rank) VALUES ";
const QString	c_seqFeatureSql = "INSERT INTO seqfeature_dbxref(seqfeature_id, dbxref_id, rank) VALUES ";

const int		c_maxQuerySize = 0x00040000; // 256 kbytes
const int		c_spacing = 2;
const QString	c_separator( ", " );

/**
**/
DbXrefInsertBuilder::DbXrefInsertBuilder( SqlServer *server ) : m_dbXRefIdx( 1 ),
	m_server( server ), m_dbXRefSize( c_dbXRefSql.length() ), m_bioentrySize( c_bioentrySql.length() ),
	m_seqFeatureSize( c_seqFeatureSql.length() )
{
	QString	sql = "SELECT MAX(dbxref_id) FROM dbxref";

	if( m_server->exec( sql ) ){
		QSqlQuery	query = m_server->getQuery();
		
		if( query.first() )
			m_dbXRefIdx = query.value( 0 ).toInt() + 1;
	}

	sql = "SELECT dbxref_id, dbname, accession FROM dbxref";

	if( m_server->exec( sql ) ){
		QSqlQuery	query = m_server->getQuery();
		
		if( query.first() ){
			do {
				QString	key = query.value( 1 ).toString() + "." + query.value( 2 ).toString();

				m_dbXRefs[key] = query.value( 0 ).toInt();
			} while( query.next() );
		}
	}
}

/**
**/
DbXrefInsertBuilder::~DbXrefInsertBuilder()
{
}

/**
**/
int DbXrefInsertBuilder::getDbXRefId( const QString &db, const QString &accession, int version )
{
	QString	key = db + "." + accession;

	if( m_dbXRefs.contains( key ) )
		return m_dbXRefs[key];

	int		val = m_dbXRefIdx++;
	QString	values = QString( "(%1, %2, %3, %4)" ).arg( val ).arg( m_server->esc( db ) )
						.arg( m_server->esc( accession ) ).arg( version );

	m_dbXRefs[key] = val;
	m_dbXRefSize += values.length() + c_spacing;

	if( m_dbXRefSize > c_maxQuerySize ){
		if( !flush() )
			return -1;
		m_dbXRefSize += values.length();
	}

	m_dbXRefValues.append( values );

	return val;
}

/**
**/
bool DbXrefInsertBuilder::getBioentryDbXRef( int bioId, int dbXRefId, int rank )
{
	qint64	key = (qint64( bioId ) << 32) + dbXRefId;
	
	if( m_bioentryRefs.contains( key ) )
		return true;

	QString	values = QString( "(%1, %2, %3)" ).arg( bioId ).arg( dbXRefId ).arg( rank );

	m_bioentryRefs.insert( key );
	m_bioentrySize += values.length() + c_spacing;

	if( m_bioentrySize > c_maxQuerySize ){
		if( !flush() )
			return false;
		m_bioentrySize += values.length();
	}

	m_bioentryValues.append( values );

	return true;
}

/**
**/
bool DbXrefInsertBuilder::getSeqFeatureDbXRef( int seqFeatureId, int dbXRefId, int rank )
{
	qint64	key = (qint64( seqFeatureId ) << 32) + dbXRefId;
	
	if( m_seqFeatureRefs.contains( key ) )
		return true;

	QString	values = QString( "(%1, %2, %3)" ).arg( seqFeatureId ).arg( dbXRefId ).arg( rank );

	m_seqFeatureRefs.insert( key );
	m_seqFeatureSize += values.length() + c_spacing;

	if( m_seqFeatureSize > c_maxQuerySize ){
		if( !flush() )
			return false;
		m_seqFeatureSize += values.length();
	}

	m_seqFeatureValues.append( values );

	return true;
}

/**
**/
bool DbXrefInsertBuilder::flush()
{
	if( m_dbXRefValues.isEmpty() && m_bioentryValues.isEmpty() && m_seqFeatureValues.isEmpty() )
		return true;

	bool	status = true;

	QFile	temp( "DbXrefInsertBuilder.txt" );

	if( !temp.open( QIODevice::WriteOnly | QIODevice::Append ) )
		return false;

	temp.write( "DbXrefInsertBuilder Flush:\n" );
	temp.putChar( '\n' );

	if( !m_dbXRefValues.isEmpty() ){
		QString	sql = c_dbXRefSql + " " + m_dbXRefValues.join( c_separator );
		
		temp.write( sql.toAscii() );
		temp.putChar( '\n' );

		if( !m_server->exec( sql ) ){
			temp.write( "Error executing statement!\n" );
			status = false;
		}

		m_dbXRefValues.clear();
		m_dbXRefSize = c_dbXRefSql.length();
	}

	if( !m_bioentryValues.isEmpty() ){
		QString	sql = c_bioentrySql + " " + m_bioentryValues.join( c_separator );
		
		temp.write( sql.toAscii() );
		temp.putChar( '\n' );

		if( !m_server->exec( sql ) ){
			temp.write( "Error executing statement!\n" );
			status = false;
		}

		m_bioentryValues.clear();
		m_bioentrySize = c_bioentrySql.length();
	}

	if( !m_seqFeatureValues.isEmpty() ){
		QString	sql = c_seqFeatureSql + " " + m_seqFeatureValues.join( c_separator );
		
		temp.write( sql.toAscii() );
		temp.putChar( '\n' );

		if( !m_server->exec( sql ) ){
			temp.write( "Error executing statement!\n" );
			status = false;
		}

		m_seqFeatureValues.clear();
		m_seqFeatureSize = c_seqFeatureSql.length();
	}

	temp.putChar( '\n' );
	temp.putChar( '\n' );

	temp.close();

	return status;
}
